<template>
  <div class="pro-table">
    <!-- 表格工具栏 -->
    <div class="table-toolbar" v-if="showToolbar">
      <div class="left">
        <slot name="toolbarLeft">
          <el-button
            v-if="showAdd"
            type="primary"
            :icon="Plus"
            @click="$emit('add')"
          >
            新增
          </el-button>
          <el-button
            v-if="showBatchDelete"
            type="danger"
            :icon="Delete"
            :disabled="!selectedRows.length"
            @click="$emit('batch-delete')"
          >
            批量删除
          </el-button>
          <slot name="buttons"></slot>
        </slot>
      </div>
      <div class="right">
        <slot name="toolbarRight">
          <el-button :icon="Refresh" circle @click="refresh" />
          <el-button
            :icon="operation ? Minus : Plus"
            circle
            @click="operation = !operation"
          />
        </slot>
      </div>
    </div>

    <!-- 操作列 -->
    <el-table
      ref="tableRef"
      v-loading="loading"
      :data="data"
      :height="height"
      :border="border"
      :stripe="stripe"
      :row-key="rowKey"
      :tree-props="treeProps"
      @selection-change="handleSelectionChange"
    >
      <!-- 选择列 -->
      <el-table-column
        v-if="showSelection"
        type="selection"
        width="55"
        align="center"
        fixed="left"
      />

      <!-- 序号列 -->
      <el-table-column
        v-if="showIndex"
        type="index"
        label="序号"
        width="60"
        align="center"
      />

      <!-- 数据列 -->
      <template v-for="column in columns" :key="column.prop">
        <el-table-column v-bind="getColumnProps(column)">
          <template #default="scope">
            <slot :name="column.prop" :row="scope.row">
              {{ getColumnValue(scope.row, column) }}
            </slot>
          </template>
        </el-table-column>
      </template>

      <!-- 操作列 -->
      <el-table-column
        v-if="operation"
        label="操作"
        :width="operationWidth"
        align="center"
        fixed="right"
      >
        <template #default="scope">
          <slot name="operation" :row="scope.row">
            <el-button
              v-if="showEdit"
              type="primary"
              link
              :icon="Edit"
              @click="$emit('edit', scope.row)"
            >
              编辑
            </el-button>
            <el-button
              v-if="showDelete"
              type="danger"
              link
              :icon="Delete"
              @click="$emit('delete', scope.row)"
            >
              删除
            </el-button>
          </slot>
        </template>
      </el-table-column>
    </el-table>

    <!-- 分页 -->
    <div class="pagination" v-if="showPagination">
      <el-pagination
        v-model:current-page="currentPage"
        v-model:page-size="pageSize"
        :page-sizes="pageSizes"
        :total="total"
        :layout="paginationLayout"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from "vue";
import { Plus, Minus, Edit, Delete, Refresh } from "@element-plus/icons-vue";
import type { TableColumnCtx } from "element-plus";

interface Column {
  prop: string;
  label: string;
  width?: number | string;
  minWidth?: number | string;
  fixed?: boolean | "left" | "right";
  sortable?: boolean;
  align?: "left" | "center" | "right";
  formatter?: (row: any, column: TableColumnCtx<any>) => string | number;
  show?: boolean;
}

interface Props {
  columns: Column[];
  data: any[];
  loading?: boolean;
  height?: string | number;
  border?: boolean;
  stripe?: boolean;
  rowKey?: string;
  treeProps?: { children: string };
  showToolbar?: boolean;
  showAdd?: boolean;
  showBatchDelete?: boolean;
  showSelection?: boolean;
  showIndex?: boolean;
  operation?: boolean;
  operationWidth?: number | string;
  showEdit?: boolean;
  showDelete?: boolean;
  showPagination?: boolean;
  pageSizes?: number[];
  paginationLayout?: string;
  total?: number;
  page?: number;
  limit?: number;
}

const props = withDefaults(defineProps<Props>(), {
  loading: false,
  border: true,
  stripe: true,
  rowKey: "id",
  treeProps: () => ({ children: "children" }),
  showToolbar: true,
  showAdd: true,
  showBatchDelete: true,
  showSelection: true,
  showIndex: true,
  operation: true,
  operationWidth: 150,
  showEdit: true,
  showDelete: true,
  showPagination: true,
  pageSizes: () => [10, 20, 30, 50],
  paginationLayout: "total, sizes, prev, pager, next, jumper",
  total: 0,
  page: 1,
  limit: 10,
});

const emit = defineEmits<{
  (e: "add"): void;
  (e: "edit", row: any): void;
  (e: "delete", row: any): void;
  (e: "batch-delete"): void;
  (e: "selection-change", selection: any[]): void;
  (e: "update:page", page: number): void;
  (e: "update:limit", limit: number): void;
  (e: "pagination", params: { page: number; limit: number }): void;
}>();

// 表格实例
const tableRef = ref();

// 选中的行
const selectedRows = ref<any[]>([]);

// 分页相关
const currentPage = computed({
  get: () => props.page,
  set: (val: number) => emit("update:page", val),
});

const pageSize = computed({
  get: () => props.limit,
  set: (val: number) => emit("update:limit", val),
});

// 处理列属性
const getColumnProps = (column: Column) => {
  const { formatter, ...rest } = column;
  return rest;
};

// 获取列值
const getColumnValue = (row: any, column: Column) => {
  if (column.formatter) {
    return column.formatter(row, column);
  }
  return row[column.prop];
};

// 选择变化
const handleSelectionChange = (selection: any[]) => {
  selectedRows.value = selection;
  emit("selection-change", selection);
};

// 分页大小变化
const handleSizeChange = (val: number) => {
  emit("pagination", { page: currentPage.value, limit: val });
};

// 页码变化
const handleCurrentChange = (val: number) => {
  emit("pagination", { page: val, limit: pageSize.value });
};

// 刷新
const refresh = () => {
  emit("pagination", { page: currentPage.value, limit: pageSize.value });
};

defineExpose({
  tableRef,
  refresh,
});
</script>

<style lang="scss" scoped>
.pro-table {
  .table-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;

    .left {
      display: flex;
      gap: 8px;
    }

    .right {
      display: flex;
      gap: 8px;
    }
  }

  .pagination {
    margin-top: 16px;
    display: flex;
    justify-content: flex-end;
  }
}
</style>
